This patch
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 27 Oct 2005 16:24:06 +0000 (17:24 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 27 Oct 2005 16:24:06 +0000 (17:24 +0100)
* adapts the Xen access control module to recent changes in the "unbound
event channel" interface and its usage
* adds checks that became necessary because of domain structures "hanging
around" in the domain list after domain destruction

This patch is tested on today's xen-unstable with Null, CHWALL, STE,
CHWALL_STE policies.

Signed-off by: Reiner Sailer <sailer@us.ibm.com>

xen/acm/acm_simple_type_enforcement_hooks.c
xen/common/acm_ops.c
xen/include/acm/acm_hooks.h

index de08f46c2a2f04bce10999040ea9c479dcfade34..41bb1b393cec04c83d940ae3101b4e69ea35c86f 100644 (file)
@@ -392,8 +392,11 @@ check_cache(struct domain *dom, domid_t rdom) {
     int i;
 
     printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
+
+    if (dom->ssid == NULL)
+        return 0;
     ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
-                         (struct acm_ssid_domain *)(dom)->ssid);
+                         (struct acm_ssid_domain *)(dom->ssid));
 
     for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
         if ((ste_ssid->ste_cache[i].valid == VALID) &&
@@ -412,6 +415,8 @@ cache_result(struct domain *subj, struct domain *obj) {
     struct ste_ssid *ste_ssid;
     int i;
     printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
+    if (subj->ssid == NULL)
+        return;
     ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
                          (struct acm_ssid_domain *)(subj)->ssid);
     for(i=0; i< ACM_TE_CACHE_SIZE; i++)
@@ -431,26 +436,34 @@ clean_id_from_cache(domid_t id)
     struct ste_ssid *ste_ssid;
     int i;
     struct domain **pd;
+    struct acm_ssid_domain *ssid;
 
     printkd("deleting cache for dom %x.\n", id);
-
     read_lock(&domlist_lock); /* look through caches of all domains */
     pd = &domain_list;
     for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
-        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
-                             (struct acm_ssid_domain *)(*pd)->ssid);
+        ssid = (struct acm_ssid_domain *)((*pd)->ssid);
+
+        if (ssid == NULL)
+            continue; /* hanging domain structure, no ssid any more ... */
+        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssid);
+        if (!ste_ssid) {
+            printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n",
+                   __func__);
+            goto out;
+        }
         for (i=0; i<ACM_TE_CACHE_SIZE; i++)
             if ((ste_ssid->ste_cache[i].valid == VALID) &&
-                (ste_ssid->ste_cache[i].id = id))
+                (ste_ssid->ste_cache[i].id == id))
                 ste_ssid->ste_cache[i].valid = FREE;
     }
+ out:
     read_unlock(&domlist_lock);
 }
 
 /***************************
  * Authorization functions
  **************************/
-
 static int 
 ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
 {      
@@ -484,19 +497,29 @@ ste_post_domain_destroy(void *subject_ssid, domid_t id)
 
 /* -------- EVENTCHANNEL OPERATIONS -----------*/
 static int
-ste_pre_eventchannel_unbound(domid_t id) {
+ste_pre_eventchannel_unbound(domid_t id1, domid_t id2) {
     struct domain *subj, *obj;
     int ret;
-    traceprintk("%s: dom%x-->dom%x.\n", 
-                __func__, current->domain->domain_id, id);
+    traceprintk("%s: dom%x-->dom%x.\n", __func__,
+                (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
+                (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
 
-    if (check_cache(current->domain, id)) {
+    if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
+    if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
+
+    subj = find_domain_by_id(id1);
+    obj  = find_domain_by_id(id2);
+    if ((subj == NULL) || (obj == NULL)) {
+        ret = ACM_ACCESS_DENIED;
+        goto out;
+    }
+    /* cache check late */
+    if (check_cache(subj, obj->domain_id)) {
         atomic_inc(&ste_bin_pol.ec_cachehit_count);
-        return ACM_ACCESS_PERMITTED;
+        ret = ACM_ACCESS_PERMITTED;
+        goto out;
     }
     atomic_inc(&ste_bin_pol.ec_eval_count);
-    subj = current->domain;
-    obj = find_domain_by_id(id);
 
     if (share_common_type(subj, obj)) {
         cache_result(subj, obj);
@@ -505,38 +528,43 @@ ste_pre_eventchannel_unbound(domid_t id) {
         atomic_inc(&ste_bin_pol.ec_denied_count); 
         ret = ACM_ACCESS_DENIED; 
     }
+  out:
     if (obj != NULL)
         put_domain(obj);
+    if (subj != NULL)
+        put_domain(subj);
     return ret;
 }
 
 static int
-ste_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
+ste_pre_eventchannel_interdomain(domid_t id)
 {
-    struct domain *subj, *obj;
+    struct domain *subj=NULL, *obj=NULL;
     int ret;
+
     traceprintk("%s: dom%x-->dom%x.\n", __func__,
-                (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
-                (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
+                current->domain->domain_id,
+                (id == DOMID_SELF) ? current->domain->domain_id : id);
 
     /* following is a bit longer but ensures that we
      * "put" only domains that we where "find"-ing 
      */
-    if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
-    if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
+    if (id == DOMID_SELF) id = current->domain->domain_id;
 
-    subj = find_domain_by_id(id1);
-    obj  = find_domain_by_id(id2);
-    if ((subj == NULL) || (obj == NULL)) {
+    subj = current->domain;
+    obj  = find_domain_by_id(id);
+    if (obj == NULL) {
         ret = ACM_ACCESS_DENIED;
         goto out;
     }
+
     /* cache check late, but evtchn is not on performance critical path */
     if (check_cache(subj, obj->domain_id)) {
         atomic_inc(&ste_bin_pol.ec_cachehit_count);
         ret = ACM_ACCESS_PERMITTED;
         goto out;
     }
+
     atomic_inc(&ste_bin_pol.ec_eval_count);
 
     if (share_common_type(subj, obj)) {
@@ -549,8 +577,6 @@ ste_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
  out:
     if (obj != NULL)
         put_domain(obj);
-    if (subj != NULL)
-        put_domain(subj);
     return ret;
 }
 
index 4f0d46c3e5685b121efaae738129548dd22fe6e6..d290b40de63c71ab77d636591d1367f8a630f27f 100644 (file)
@@ -133,7 +133,10 @@ long do_acm_op(struct acm_op * u_acm_op)
             struct domain *subj = find_domain_by_id(op->u.getssid.id.domainid);
             if (!subj)
                 return -ESRCH; /* domain not found */
-
+            if (subj->ssid == NULL) {
+                put_domain(subj);
+                return -ESRCH;
+            }
             ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
             put_domain(subj);
         } else
@@ -167,6 +170,10 @@ long do_acm_op(struct acm_op * u_acm_op)
                 ret = -ESRCH; /* domain not found */
                 goto out;
             }
+            if (subj->ssid == NULL) {
+                put_domain(subj);
+                ret = -ESRCH;
+            }
             ssidref1 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
             put_domain(subj);
         } else {
@@ -182,6 +189,10 @@ long do_acm_op(struct acm_op * u_acm_op)
                 ret = -ESRCH; /* domain not found */
                 goto out;
             }
+            if (subj->ssid == NULL) {
+                put_domain(subj);
+                return -ESRCH;
+            }
             ssidref2 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref;
             put_domain(subj);
         } else {
index a79acf295265e2d3ba3e38e1766b12cbc9a58771..011669373dc54c8ee914b113b67bc3e8b5c20822 100644 (file)
@@ -100,10 +100,10 @@ struct acm_operations {
     void (*fail_domain_create)         (void *subject_ssid, ssidref_t ssidref);
     void (*post_domain_destroy)        (void *object_ssid, domid_t id);
     /* event channel control hooks  (can be NULL) */
-    int  (*pre_eventchannel_unbound)      (domid_t id);
-    void (*fail_eventchannel_unbound)     (domid_t id);
-    int  (*pre_eventchannel_interdomain)  (domid_t id1, domid_t id2);
-    int  (*fail_eventchannel_interdomain) (domid_t id1, domid_t id2);
+    int  (*pre_eventchannel_unbound)      (domid_t id1, domid_t id2);
+    void (*fail_eventchannel_unbound)     (domid_t id1, domid_t id2);
+    int  (*pre_eventchannel_interdomain)  (domid_t id);
+    void (*fail_eventchannel_interdomain) (domid_t id);
     /* grant table control hooks (can be NULL)  */
     int  (*pre_grant_map_ref)          (domid_t id);
     void (*fail_grant_map_ref)         (domid_t id);
@@ -193,31 +193,31 @@ static inline void acm_post_domain_destroy(void *object_ssid, domid_t id)
     return;
 }
 
-static inline int acm_pre_eventchannel_unbound(domid_t id)
+static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
 {
     if ((acm_primary_ops->pre_eventchannel_unbound != NULL) && 
-        acm_primary_ops->pre_eventchannel_unbound(id))
+        acm_primary_ops->pre_eventchannel_unbound(id1, id2))
         return ACM_ACCESS_DENIED;
     else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) && 
-             acm_secondary_ops->pre_eventchannel_unbound(id)) {
+             acm_secondary_ops->pre_eventchannel_unbound(id1, id2)) {
         /* roll-back primary */
         if (acm_primary_ops->fail_eventchannel_unbound != NULL)
-            acm_primary_ops->fail_eventchannel_unbound(id);
+            acm_primary_ops->fail_eventchannel_unbound(id1, id2);
         return ACM_ACCESS_DENIED;
     } else
         return ACM_ACCESS_PERMITTED;
 }
 
-static inline int acm_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
+static inline int acm_pre_eventchannel_interdomain(domid_t id)
 {
     if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) &&
-        acm_primary_ops->pre_eventchannel_interdomain(id1, id2))
+        acm_primary_ops->pre_eventchannel_interdomain(id))
         return ACM_ACCESS_DENIED;
     else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) &&
-             acm_secondary_ops->pre_eventchannel_interdomain(id1, id2)) {
+             acm_secondary_ops->pre_eventchannel_interdomain(id)) {
         /* roll-back primary */
         if (acm_primary_ops->fail_eventchannel_interdomain != NULL)
-            acm_primary_ops->fail_eventchannel_interdomain(id1, id2);
+            acm_primary_ops->fail_eventchannel_interdomain(id);
         return ACM_ACCESS_DENIED;
     } else
         return ACM_ACCESS_PERMITTED;
@@ -234,10 +234,22 @@ static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid)
             current->domain->ssid, op->u.createdomain.ssidref);
         break;
     case DOM0_DESTROYDOMAIN:
+        if (*ssid != NULL) {
+            printkd("%s: Warning. Overlapping destruction.\n", 
+                    __func__);
+            return -EACCES;
+        }
         d = find_domain_by_id(op->u.destroydomain.domain);
         if (d != NULL) {
             *ssid = d->ssid; /* save for post destroy when d is gone */
-            /* no policy-specific hook */
+            if (*ssid == NULL) {
+                printk("%s: Warning. Destroying domain without ssid pointer.\n", 
+                       __func__);
+                put_domain(d);
+                return -EACCES;
+            }
+            d->ssid = NULL; /* make sure it's not used any more */
+             /* no policy-specific hook */
             put_domain(d);
             ret = 0;
         }
@@ -248,7 +260,7 @@ static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid)
     return ret;
 }
 
-static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid) 
+static inline void acm_post_dom0_op(dom0_op_t *op, void **ssid)
 {
     switch(op->cmd) {
     case DOM0_CREATEDOMAIN:
@@ -261,7 +273,8 @@ static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid)
     case DOM0_DESTROYDOMAIN:
         acm_post_domain_destroy(ssid, op->u.destroydomain.domain);
         /* free security ssid for the destroyed domain (also if null policy */
-        acm_free_domain_ssid((struct acm_ssid_domain *)ssid);
+        acm_free_domain_ssid((struct acm_ssid_domain *)(*ssid));
+        *ssid = NULL;
         break;
     }
 }
@@ -282,12 +295,13 @@ static inline int acm_pre_event_channel(evtchn_op_t *op)
 
     switch(op->cmd) {
     case EVTCHNOP_alloc_unbound:
-        ret = acm_pre_eventchannel_unbound(op->u.alloc_unbound.dom);
+        ret = acm_pre_eventchannel_unbound(
+                  op->u.alloc_unbound.dom,
+                  op->u.alloc_unbound.remote_dom);
         break;
     case EVTCHNOP_bind_interdomain:
         ret = acm_pre_eventchannel_interdomain(
-            current->domain->domain_id,
-            op->u.bind_interdomain.remote_dom);
+                  op->u.bind_interdomain.remote_dom);
         break;
     default:
         ret = 0; /* ok */